package cn.yangliu.utils;

import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import javax.crypto.SecretKey;
import javax.crypto.spec.SecretKeySpec;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandom;

/**
 * <pre>职责: 用户加密和解密算法
 * 使用方法：
 * </pre>
 *
 * @author sunsn 2016-1-5 下午02:54:43
 * @see #
 * @since <pre>修改记录（修改时间、修改人、修改内容、修改原因）</pre>
 */
public class CryptUtils {

    /**
     * 消息摘要算法名称：MD5
     */
    public static final String DIGEST_MD5 = "MD5";

    /**
     * 计算消息摘要值
     *
     * @param algorithm - 算法，如：MD5, SHA1，推荐使用SHA1
     * @param text
     * @return - 16进制字符串
     * @throws Exception
     */
    public static String generateDigest(String algorithm, String text) {
        try {
            MessageDigest digest = MessageDigest.getInstance(algorithm);
            byte[] value = digest.digest(text.getBytes("UTF-8"));
            return parseByteToHexString(value).toLowerCase();
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }

    /**
     * 计算消息摘要值
     * MD5
     *
     * @param text
     * @return - 16进制字符串
     * @throws Exception
     */
    public static String generateDigest(String text) {
        return generateDigest(DIGEST_MD5, text);
    }

    /**
     * 将字节数组转换为16进制字符串
     *
     * @param content
     * @return
     * @throws Exception
     * @author Julian
     */
    public static String parseByteToHexString(byte[] content) {
        if (content == null) throw new IllegalArgumentException("the parameter is null.");

        String hex = null;
        StringBuffer buffer = new StringBuffer();
        for (int i = 0; i < content.length; i++) {
            hex = Integer.toHexString(content[i] & 0xFF);
            if (hex.length() == 1) hex = '0' + hex;

            buffer.append(hex.toUpperCase());
        }

        return buffer.toString();
    }


    public static String base64_encode(String str) {
        return new sun.misc.BASE64Encoder().encode(str.getBytes());
    }

    public static String base64_decode(String str) {

        sun.misc.BASE64Decoder decoder = new sun.misc.BASE64Decoder();
        if (str == null)
            return null;
        try {
            return new String(decoder.decodeBuffer(str));
        } catch (IOException e) {
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }


    /**
     * AES加密字符串
     *
     * @param content
     *            需要被加密的字符串
     * @param key
     *            加密需要的密码
     * @return 密文
     */
    public static String encryptByAES(String content, String key) {
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者

            kgen.init(128, new SecureRandom(key.getBytes()));// 利用用户密码作为随机数初始化出
            // 128位的key生产者
            //加密没关系，SecureRandom是生成安全随机数序列，password.getBytes()是种子，只要种子相同，序列就一样，所以解密只要有password就行

            SecretKey secretKey = kgen.generateKey();// 根据用户密码，生成一个密钥

            byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥，如果此密钥不支持编码，则返回
            // null。

            SecretKeySpec sks = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥

            Cipher cipher = Cipher.getInstance("AES");// 创建密码器

            byte[] byteContent = content.getBytes("utf-8");

            cipher.init(Cipher.ENCRYPT_MODE, sks);// 初始化为加密模式的密码器

            byte[] bytes = cipher.doFinal(byteContent);// 加密

            return parseByte2HexStr(bytes);

        } catch (Exception e) {
           throw new RuntimeException(e);
        }
    }

    /**
     * 解密AES加密过的字符串
     *
     * @param content
     *            AES加密过过的内容
     * @param key
     *            加密时的密码
     * @return 明文
     */
    public static String decryptByAES(String content, String key) {
        byte [] bytes=parseHexStr2Byte(content);
        try {
            KeyGenerator kgen = KeyGenerator.getInstance("AES");// 创建AES的Key生产者
            kgen.init(128, new SecureRandom(key.getBytes()));
            SecretKey secretKey = kgen.generateKey();// 根据用户密码，生成一个密钥
            byte[] enCodeFormat = secretKey.getEncoded();// 返回基本编码格式的密钥
            SecretKeySpec sks = new SecretKeySpec(enCodeFormat, "AES");// 转换为AES专用密钥
            Cipher cipher = Cipher.getInstance("AES");// 创建密码器
            cipher.init(Cipher.DECRYPT_MODE, sks);// 初始化为解密模式的密码器
            byte[] result = cipher.doFinal(bytes);
            return new String(result); // 明文

        } catch (Exception e) {
         throw new RuntimeException(e);
        }
    }

    /**将二进制转换成16进制
     * @param buf
     * @return
     */
    public static String parseByte2HexStr(byte buf[]) {
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < buf.length; i++) {
            String hex = Integer.toHexString(buf[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            sb.append(hex.toUpperCase());
        }
        return sb.toString();
    }

    /**将16进制转换为二进制
     * @param hexStr
     * @return
     */
    public static byte[] parseHexStr2Byte(String hexStr) {
        if (hexStr.length() < 1)
            return null;
        byte[] result = new byte[hexStr.length()/2];
        for (int i = 0;i< hexStr.length()/2; i++) {
            int high = Integer.parseInt(hexStr.substring(i*2, i*2+1), 16);
            int low = Integer.parseInt(hexStr.substring(i*2+1, i*2+2), 16);
            result[i] = (byte) (high * 16 + low);
        }
        return result;
    }

    public static void main(String[] args) {
        System.out.println(encryptByAES("123456","YGKKJYXGS_QB1988"));

        System.out.println(decryptByAES("D7907B504C38EE1F9E98831D44B517C0","YGKKJYXGS_QB1988"));
    }

}
